/**
 *  Copyright (C) 2013  Piotr Szczepa�ski
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package edu.pw.elka.gtsna.centrality.degree;

import java.util.LinkedHashSet;
import java.util.Set;

import edu.pw.elka.gtsna.centrality.NodeCentrality;
import edu.pw.elka.gtsna.coalitionalgames.CoalitionalGame;
import edu.pw.elka.gtsna.community_detection.CommunityStructure;
import edu.pw.elka.gtsna.graph.DirectedGraph;

/**
 * @author Piotr Lech Szczepa�ski
 * @author P.Szczepanski@ii.pw.edu.pl 
 *
 *	This centrality measure was proposed in the article 
 *	AAMAS 2014, Szczepa�ski, Michalak TODO
 *
 */
public class OVCitationDegreeCentrality extends NodeCentrality implements CoalitionalGame {
	CommunityStructure partition;
	
	
	private DirectedGraph graph(){
		return ((DirectedGraph) this.graph);
	}
	
	public OVCitationDegreeCentrality(DirectedGraph graph, CommunityStructure partition) {
		super(graph);
		this.partition = partition;
	}

	public double getCommunityCentrality(Set<Integer> community){
		double value = 0.0;
		for (int node: community){
			value+=getCentrality(node);
		}
		return value;
	}
	
	public double initialValue(int node){
		return (double)graph().getInDegree(node);
	}
	
	@Override
	public void computeCentrality() {
		for(int node: graph().getAllNodes()){
			int Cj = partition.getNodeCommunityNumber(node);
			double value = 0.0;
			for(int neighbour: graph().getInNeigbours(node)){
				// if node and neighbour are from the same community
				if (partition.getNodeCommunityNumber(neighbour) == Cj) {
					value+= initialValue(neighbour)/( (1.0 + graph().getAmongPartitionOutDegree(neighbour, partition))*
								  (1.0 + graph().getWithinPartitionOutDegree(neighbour,Cj, partition)));
				} else {
					value+= initialValue(neighbour)/( (1.0 + graph().getAmongPartitionOutDegree(neighbour, partition))*
							  (graph().getWithinPartitionOutDegree(neighbour,Cj, partition)));
				}
			}
			value+= (initialValue(node)-( initialValue(node)*(1.0+graph().getAmongPartitionOutDegree(node, partition))*
					  (1.0+graph().getIntraCommunityDegree(node, partition, Cj)))) /
					  ( (1.0 + graph().getAmongPartitionOutDegree(node, partition))*
							  (1.0+graph().getWithinPartitionOutDegree(node,Cj, partition)));
			
    		centralities.put(node, value) ;
    	}
	}


	@Override
	public double v(Set<Integer> C) {
		double value = 0.0;
		for(int node: graph().getInNeigbours(C)){
			value+=initialValue(node);
		}
		return value;
	}

	@Override
	public double MC(Set<Integer> C, int a) {
		Set<Integer> S = new LinkedHashSet<Integer>(C);
		S.add(a);
		return (v(S)-v(C));
	}


	@Override
	public Set<Integer> getAgents() {
		return graph.getAllNodes();
	}

	@Override
	public int size() {
		return graph.getNumOfNodes();
	}

	/* (non-Javadoc)
	 * @see edu.pw.elka.gtsna.coalitionalgames.CharacteristicFunctionComputable#succesiveMC(int)
	 */
	@Override
	public double succesiveMC(int a) {
		// TODO Auto-generated method stub
		return 0;
	}

	/* (non-Javadoc)
	 * @see edu.pw.elka.gtsna.coalitionalgames.CharacteristicFunctionComputable#reset()
	 */
	@Override
	public void reset() {
		// TODO Auto-generated method stub
		
	}
	
}
